#include "CUitl.h"

#include <algorithm>
#include <chrono>
#include <mutex>
#include <thread>
namespace CUitl {

std::mutex cuitlmutex_;
bool str2json(std::string str, Json::Value &v) {
    Json::Reader reader;
    Json::Value temp;
    if (!reader.parse(str, temp)) return false;
    v = temp;
    return true;
}
std::string json2str(Json::Value &v, bool needFormat) {
    std::lock_guard<std::mutex> lk(cuitlmutex_);
    if (needFormat) {
        return v.toStyledString();
    }
    Json::FastWriter FastWriter;
    return FastWriter.write(v);
}
bool file2json(std::string path, Json::Value &v) {
    std::lock_guard<std::mutex> lk(cuitlmutex_);
    v.clear();
    struct stat buffer;
    int ret = stat(path.c_str(), &buffer);
    if (ret != 0) {
        return false;
    }
    Json::Reader r;
    std::ifstream ifs(path.c_str());
    if (!ifs.is_open()) {
        return false;
    }
    if (!r.parse(ifs, v)) {
        ifs.close();
        return false;
    }
    ifs.close();
    return true;
}

bool str2file(std::string path, const std::string data) {
    std::lock_guard<std::mutex> lk(cuitlmutex_);
    FILE *fp = fopen(path.c_str(), "w");
    if (fp) {
        fwrite(data.data(), data.size(), 1, fp);
        fflush(fp);
        fclose(fp);
        sync();
        return true;
    }
    return false;
}
void StringReplace(std::string &strBase, std::string strSrc,
                   std::string strDes) {
    std::string::size_type pos = 0;
    std::string::size_type srcLen = strSrc.size();
    std::string::size_type desLen = strDes.size();
    pos = strBase.find(strSrc, pos);
    while ((pos != std::string::npos)) {
        strBase.replace(pos, srcLen, strDes);
        pos = strBase.find(strSrc, (pos + desLen));
    }
}

void StringToupper(std::string &strdata) {
    std::transform(strdata.begin(), strdata.end(), strdata.begin(), ::toupper);
}

void StringTolower(std::string &strdata) {
    std::transform(strdata.begin(), strdata.end(), strdata.begin(), ::tolower);
}

uint64_t gettimestatmp() {
    return std::chrono::duration_cast<std::chrono::seconds>(
               std::chrono::system_clock::now().time_since_epoch())
        .count();
}

uint64_t gettimestatmpms() {
    return std::chrono::duration_cast<std::chrono::milliseconds>(
               std::chrono::system_clock::now().time_since_epoch())
        .count();
}
static size_t CurlWriteStdString(void *contents, size_t size, size_t nmemb,
                                 std::string *s) {
    size_t newLength = size * nmemb;
    try {
        s->append(static_cast<char *>(contents), newLength);
    } catch (std::bad_alloc &e) {
        std::cout << e.what() << std::endl;
        return 0;
    }
    return newLength;
}
bool ThirdSendCmd(Json::Value v, Json::Value &r) {
    CURL *curl = curl_easy_init();
    if (!curl) {
        return false;
    }
    CURLcode res;
    std::string response;
    std::string type("Content-Type: application/json");
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, type.c_str());
    Json::FastWriter FastWriter;
    std::string senddata = FastWriter.write(v);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, senddata.c_str());
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:9000/api/v1.0/main");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteStdString);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);  //请求超时时长

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
        curl_easy_cleanup(curl);
        curl = NULL;
        return false;
    }
    str2json(response, r);

    curl_easy_cleanup(curl);
    curl = NULL;
    return true;
}
std::string timestamp2str(time_t t) {
    struct tm *local_time;
    local_time = localtime(&t);
    char buf[80];
    std::strftime(buf, 80, "%Y-%m-%d %H:%M:%S", local_time);
    return std::string(buf);
}

time_t str2timestamp(std::string time) {
    struct tm stm;
    strptime(time.c_str(), "%Y-%m-%d %H:%M:%S", &stm);
    time_t t = mktime(&stm);
    return t;
}

std::string GetSystemUuid() {
    std::lock_guard<std::mutex> lk(cuitlmutex_);
    char uuid[39] = {0};
    int fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
    if (fd >= 0) {
        int ret = read(fd, uuid, 36);
        close(fd);
    }
    return std::string(uuid);
}

size_t getfilesize(const std::string &file_name) {
    std::ifstream in(file_name.c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    in.close();
    return size;  //单位是：byte
}

int GetRandomNum(int min, int max) {
    srand(static_cast<unsigned int>(time(0)));
    return ((random() % (max - min)) + min);
}

std::string data2base64(const char *data, int size) {
    char *pbase64 = (char *)calloc(size / 3 * 4 + 8, sizeof(char));
    mg_base64_encode((const unsigned char *)data, size, pbase64);
    int len = 0;
    if (size % 3 == 0) {
        len = size / 3 * 4;
    } else {
        len = (size / 3 + 1) * 4;
    }
    std::string res(pbase64, len);
    free(pbase64);
    return res;
}
int base642data(std::string &str, char *data) {
    int ret = 0;
    int length = str.size();

    ret =
        mg_base64_decode((const char *)str.c_str(), str.size(), data);

    if (ret == str.size()) {
        if (std::string::npos != str.find("==", length - 4)) {
            length = length / 4 * 3 - 2;
        } else if (std::string::npos != str.find("=", length - 4))
            length = length / 4 * 3 - 1;
        else
            length = length / 4 * 3;
    } else {
        return 0;
    }
    return length;
}

// std::string url_encode(const char *data, int size) {
//     char buf[1024];
//     mg_str mgstr_in, mgstr_out;
//     mgstr_in.ptr = data;
//     mgstr_in.len = size;
//     mgstr_out = mg_url_encode(mgstr_in.ptr,(size_t)1, buf, mgstr_in.len);
//     return std::string(mgstr_out.ptr, mgstr_out.len);
// }

int SaveFile(const char *buff, int len, const char *filename) {
    FILE *stream;
    if ((stream = fopen(filename, "wb")) == NULL) {
        std::cout << filename << std::endl;
        fprintf(stderr, "Cannot open output file.\n");
        return 1;
    }
    fwrite(buff, len, 1, stream);
    fclose(stream);
    return 0;
}

bool AddDir(std::string dir) {
    std::string cmd = std::string("mkdir -p ");
    cmd += dir;
    std::cout << cmd << std::endl;
    system(cmd.c_str());
    return true;
}

// std::string GetMd5(const char *data, int len) {
//     cs_md5_ctx md5_ctx;
//     cs_md5_init(&md5_ctx);
//     cs_md5_update(&md5_ctx, (const unsigned char *)data, len);
//     uint8_t digest[16];
//     cs_md5_final(digest, &md5_ctx);

//     char md5[32];
//     cs_to_hex(md5, (const unsigned char *)digest, 16);
//     return std::string(md5, 32);
// }

std::string PostImgBase64(std::string url) {
    CURL *curl = curl_easy_init();
    if (!curl) return "";

    // std::cout << "POST URL: " << url << std::endl;
    CURLcode res;
    std::string response;
    // struct curl_slist *headers = NULL;
    // headers = curl_slist_append(headers, c_type.c_str());

    // curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteStdString);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L);
    // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    // curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    res = curl_easy_perform(curl);

    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
        curl_easy_cleanup(curl);
        // curl_slist_free_all(headers);
        return "";
    }

    curl_easy_cleanup(curl);
    return data2base64(response.c_str(), response.size());
}
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int fm_systembyvf(const char *cmdstring) {
    pid_t pid;
    int status;

    if (cmdstring == NULL) {
        return (1);  // 如果cmdstring为空，返回非零值，一般为1
    }

    if ((pid = vfork()) < 0) {
        status = -1;  // fork失败，返回-1
    } else if (pid == 0) {
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        // exec执行失败返回127，注意exec只在失败时才返回现在的进程，成功的话现在的进程就不存在啦~~
        _exit(127);
    } else {
        // note: 父进程
        while (waitpid(pid, &status, 0) < 0) {
            if (errno != EINTR) {
                status = -1;  // 如果waitpid被信号中断，则返回-1
                break;
            }
        }
    }
    return status;  // 如果waitpid成功，则返回子进程的返回状态
}

int fm_systembyio(const char *cmdstring) {
    FILE *fp;
    int res;
    char buf[1024] = {0};
    if (cmdstring == NULL) {
        printf("system cmd is NULL!\n");
        return -1;
    }
    if ((fp = popen(cmdstring, "r")) == NULL) {
        perror("popen");
        printf("popen error: %s/n", strerror(errno));
        return -1;
    } else {
        while (fgets(buf, sizeof(buf), fp)) {
            printf("%s", buf);
        }
        if ((res = pclose(fp)) == -1) {
            printf("close popen file pointer fp error!\n");
            return res;
        } else if (res == 0) {
            return res;
        } else {
            printf("popen res is :%d\n", res);
            return res;
        }
    }
}
}  // namespace CUitl
